
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "subband_proc.h"
#include "fftwrap.h"

typedef struct audioModule_
{
    /**/
    void  *fft_lookup;
    int frame_size;
    int window_size;
    float *win;
    float *winbuf;
    float *overlap;
    float *E; // echo
    float *e;

}audioModule;

// generate windows
static void SqrtHanning(float *win, int len)
{
    int n; float PI = 3.1415926;
	for (n=0; n<len/2+1; n++)
	{
		win[n] = sqrtf(0.5*(1-cos(2*PI*n/len)));
	}
	for (n=1; n<len/2; n++)
	{
		win[len/2+n] = win[len/2-n];
	}
}

// add window
static void window_data(float *in, float *out, float *win, int len)
{
    int i;
    for (i = 0; i < len; i++)
    {
        out[i] = in[i] * win[i];
    }
}


void *subband_create(int framesize)
{
    audioModule *self = (audioModule *)malloc(sizeof(audioModule));
    self->frame_size = framesize;
    self->window_size = 2*framesize;
    int N = 2*framesize;
    self->fft_lookup = spx_fft_init(N);

    self->win = (float*)malloc(N*sizeof(float));
    SqrtHanning(self->win, N);
    self->overlap = (float*)malloc(self->frame_size*sizeof(float));
    for (int n=0; n<self->frame_size; n++) {
        self->overlap[n] = 0.0f;
    }
    self->winbuf = (float*)malloc(N*sizeof(float));
    /**/
    self->e = (float*)malloc(N*sizeof(float));
    self->E = (float*)malloc(N*sizeof(float));
    
    return (void *)self;
}

int subband_process(void *obj, short *ref, short *mic, short *aec)
{
    audioModule *self = (audioModule *)obj;    
    int N = self->window_size;
    memcpy(self->e, self->e+self->frame_size, sizeof(float)*(self->frame_size));    
    for (int n=0; n<self->frame_size; n++) {
        self->e[self->frame_size + n] = (float)mic[n];
    }
    window_data(self->e, self->winbuf, self->win, N);
    
    spx_fft_float(self->fft_lookup, self->winbuf, self->E);


    self->E[0] = 0.0f;
    
    spx_ifft_float(self->fft_lookup, self->E, self->winbuf);

    float tmp;
    for (int n=0; n<self->frame_size; n++) {
        tmp = self->winbuf[n]*self->win[n] + self->overlap[n];
        aec[n] = (short)tmp;
    }
    for (int n=self->frame_size; n<N; n++) {
        self->overlap[n-self->frame_size] = self->winbuf[n]*self->win[n];
    }

    return 0;
}

void subband_destory(void *obj)
{
    audioModule *self = (audioModule *)obj;     
    spx_fft_destroy(self->fft_lookup);    
    free(self->win);
    free(self->overlap);
    free(self->winbuf);
    free(self->E);
    free(self->e);
    free(self);
}